package com.cee.admin.common;


import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cee.admin.common.utils.HttpServletUtils;
import com.cee.admin.log.annotations.OperateLog;
import com.cee.admin.log.util.OperateLogUtils;
import com.cee.common.disk.FileStorageFacadeExt4;
import com.cee.common.disk.SaveFileModeEnums;
import com.cee.common.disk.UploadFileDirProperties;
import com.cee.common.domain.TreeNode;
import com.cee.common.exception.DiskServiceException;
import com.cee.common.exception.GlobalException;
import com.cee.common.web.result.Result;
import com.cee.ds.modules.sys.service.ISysConfAreaService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;


/**
 * 一些公共的控制器
 *
 * @author rxliuli
 * @date 2018/6/4
 */
@Controller
@RequestMapping("/api/v1/common")
@Slf4j
@Tag(name = "公共接口")
public class CommonController extends BaseController {

    @Autowired
    private FileStorageFacadeExt4 fileStorageFacadeExt4;

    @Autowired
    private UploadFileDirProperties uploadFileDirProperties;

    @Autowired
    private ISysConfAreaService areaService;

    private String tmpRootFilePath;

    private String permanentRootFilePath;

    @PostConstruct
    public void init() {
        //检查是否配置上传的根目录
        checkRootFilePathProperty(false);
    }

    /**
     * 检查根文件目录属性是否配置
     */
    private void checkRootFilePathProperty(boolean throwEx) {
        tmpRootFilePath = uploadFileDirProperties.getTmp();
        permanentRootFilePath = uploadFileDirProperties.getPermanent();
        if (StringUtils.isBlank(tmpRootFilePath)) {
            log.error("Please configure the 'disk.storage.root-dir.tmp' property, otherwise uploading files will fail!");
            if (throwEx) {
                throw new GlobalException("don’t configure tmpRootDir property,upload files will fail!");
            }
        }

        if (StringUtils.isBlank(permanentRootFilePath)) {
            log.error("Please configure the 'disk.storage.root-dir.permanent' property, otherwise uploading files will fail!");
            if (throwEx) {
                throw new GlobalException("don’t configure permanentRootDir property,upload files will fail!");
            }
        }
    }

    /**
     * 重定向到某个页面
     */
    @GetMapping(path = "redirect")
    public String redirect(String pagePath) {
        return "redirect:" + pagePath;
    }

    /**
     * 转发到指定的视图
     */
    @GetMapping(path = "forward")
    public String forward(String pagePath) {
        return pagePath;
    }

    @GetMapping("/key")
    @Operation(summary = "获取key")
    @ResponseBody
    public Result<String> key() {
        return success(IdWorker.getIdStr());
    }

    /**
     * 下载文件
     * 可以用作图片 url 路径
     *
     * @param filePath 相对路径
     */
    @GetMapping(path = "/download")
    @ResponseBody
    @OperateLog(logArgs = true)
    @Operation(summary = "下载文件")
    public void download(@Parameter(description = "文件路径") String filePath,
                         @Parameter(description = "自定义要下载文件的文件名") String filename,
                         @Parameter(description = "要下载文件存储类型（temp-临时，permanent-永久）") @RequestParam(defaultValue = "permanent") String type) {
        if (SaveFileModeEnums.TEMP.mode.equals(type)) {
            OperateLogUtils.disableCurrentLog();
        }
        try (InputStream fileInputStream = fileStorageFacadeExt4.readFileInputStream(filePath, SaveFileModeEnums.getMode(type))) {
            if (StringUtils.isBlank(filename)) {
                filename = fileStorageFacadeExt4.getFileName(filePath);
            }
            IOUtils.copy(fileInputStream, wrapDownloadResponse(filename));
        } catch (DiskServiceException | IOException e) {
            log.error("获取文件下载链接错误", e);
            HttpServletResponse response = HttpServletUtils.getResponse();
            response.addHeader("File-Error", "true");
            response.addHeader("Access-Control-Expose-Headers", "File-Error");
            throw new GlobalException("获取文件下载链接错误", e);
        }
    }

    /**
     * 下载文件（无需登录）
     * 可以用作图片 url 路径
     *
     * @param filePath 相对路径
     */
    @GetMapping(path = "/public/download")
    @ResponseBody
    @Operation(summary = "下载文件")
    public void downloadPublic(@Parameter(description = "文件路径") String filePath,
                               @Parameter(description = "自定义要下载文件的文件名") String filename,
                               @Parameter(description = "要下载文件存储类型（temp-临时，permanent-永久）") @RequestParam(defaultValue = "permanent") String type) {
        download(filePath, filename, type);
    }

    /**
     * 上传单个文件 保存到临时文件
     *
     * @param file 要上传的单个文件
     * @return 上传成功后的文件相对路径
     */
    @PostMapping(path = "/upload-file")
    @ResponseBody
    @OperateLog(logResultData = true)
    @Operation(summary = "上传文件")
    public Result<String> uploadFile(MultipartFile file) {
        if (file == null) {
            throw new GlobalException(400, "文件不存在或上传路径不存在");
        }
        if (file.isEmpty()) {
            return error("上传失败，文件不存在");
        }

        try (InputStream inputStream = file.getInputStream()) {
            final String relativePath = fileStorageFacadeExt4.saveFileWithOriginalFilename(inputStream, file.getOriginalFilename(), tmpRootFilePath, SaveFileModeEnums.TEMP);
            return success(relativePath);
        } catch (Exception e) {
            log.error("file upload failed", e);
            return error("上传文件失败");
        }
    }


    /**
     * 上传多个文件
     *
     * @param files 多个文件列表
     * @return 上传成功后的文件相对路径列表
     */
    @PostMapping(path = "/upload-files")
    @ResponseBody
    @OperateLog(logResultData = true)
    @Operation(summary = "上传多个文件")
    public Result<List<String>> uploadFiles(@RequestParam("file") List<MultipartFile> files) {
        final List<String> filePathList = new ArrayList<>(files.size());
        for (final MultipartFile file : files) {
            if (file.isEmpty()) {
                return error("文件不存在");
            } else {
                try (InputStream inputStream = file.getInputStream()) {
                    final String relativePath = fileStorageFacadeExt4.saveFile(inputStream, file.getOriginalFilename(), tmpRootFilePath, SaveFileModeEnums.TEMP);
                    filePathList.add(relativePath);
                } catch (Exception e) {
                    log.error("file upload failed ", e);
                    return error("上传文件失败");
                }
            }
        }
        return success(filePathList);
    }

    @GetMapping("/region/tree")
    @Operation(summary = "获取树形结构的行政区域")
    @ResponseBody
    public Result<List<TreeNode>> regionTree() {
        return success(areaService.tree());
    }
}
